<?php

namespace App\Http\Controllers;

use App\Jobs\SendEmail;
use Illuminate\Support\Facades\Cache;

class UsersController extends Controller
{

    public function cacheConfig(){
        Cache::flush();
        Cache::put('tesvrert123',2222222, now()->addMinutes(10));
        Cache::rememberForever('users', function (){
            return \App\User::where('id',5)->get();
        });

        info(123456789);
        dd(Cache::get("tesvrert123"));


        $cc=[];
        var_dump(substr($cc, 123));
        var_dump(sha1($cc));
        var_dump(substr($cc, 123) === sha1($cc));die;

        if(intval('123456789dfs') == '123456789'){
            dd(12344); //true
        }
        dd(444444);
        var_dump("1" == 0.9999999999999999);//false
        var_dump("1" == 0.99999999999999999);//true
        var_dump("61529519452809720693702583126814" == "61529519452809720000000000000000"); // true

        $json_str = '{"user":true,"pass":true}';
        $data = json_decode($json_str,true);
        $data = [
            'user' => true,
            'pass' => true,
        ];

        if ($data['user'] == 'admin' && $data['pass']=='secirity')
        {
            dd(5555555);//true
        }else{
            dd(111111111);
        }

    }

    public function sendMessage(){

        $users = \App\User::where('id',5)->get();
        foreach ($users as $user){
            $this->dispatch(new SendEmail($user));
            info($user->email);
        }
        dd(12334);

    }

    /*
     * 自学serviceProvider的执行过程
     * */
    public function serviceProvider(){

        //    $hash = password_hash('password', PASSWORD_DEFAULT);//每次加密，会使用不同的盐值，当然可以传入第三个参数：盐值，cost是深度，深度越大，加密执行的时间越长
//    if(password_verify('password', $hash)){//可以直接使用verify来验证加密的结果
//
//    }
//    dd($hash);

        app('Illuminate\Hashing\BcryptHasher')->make('12345');
        dd(app('hash')->make('12345')); //假如app中传的是个key，这时候操作有：1.找到key对应serviceprovider中的register方法 2.执行绑定的匿名函数（bind方法的第二个参数）
        //假如是类， 1.先去application中查找对应的key， 2.根据key找到对应的provider 3 执行callback

        dd(app()['hash']->make('12345'));
        dd(Hash::make('12345'));



        dd(app('Illuminate\Contracts\Config\Repository'));
        dd(app('Illuminate\Config\Repository'));
        dd(app('config'));




        $user = \App\User::where('id',5)->first();
        dd(app('emailService')->send($user));
        app('emailservice')->send($user);

        dd(12345);

        app('files')->get(__DIR__.'/api.php'); //直接通过设置好的键files对应的registerNativeFileSystem服务来实例化Filesystem，并可以调用对象的方法
        /*
            这里相当于： $filesystem = new \Illuminate\Filesystem\Filesystem();
                       $filesystem->get(__DIR__.'/api.php');
            所以使用Provider的好处就提现出来了，假如Filesystem还依赖其他的类，使用Provider可以直接在设置键files的时候实例化，从而避免多次使用new
                 */
        app()->make('files')->get(__DIR__.'/api.php');
    }

    public function testFileSystem(){

        $file = '/home/vagrant/code/zhangfengxia/public/template/药物浏览记录导出.xlsx';
        dd(stat($file),pathinfo($file));
        /*
        前者是文件的信息，后者是文件路径的信息
          [
                  "dirname" => "/www/htdocs/inc"
                  "basename" => "lib.inc.php"
                  "extension" => "php"
                  "filename" => "lib.inc"
                ]
         * */

        if (file_exists($file)) {
            header('Content-Description: File Transfer');
            header('Content-Type: application/octet-stream');
            header('Content-Disposition: attachment; filename="'.basename($file).'"');
            header('Expires: 0');
            header('Cache-Control: must-revalidate');
            header('Pragma: public');
            header('Content-Length: ' . filesize($file));
            readfile($file); //读取文件并写入到输出缓冲,所以会在浏览器界面底部显示正在下载excel文件标识，之后会下载文件成功，其实相当于将数据写入到缓冲区并输出缓冲区内容
            exit;
        }

        $path_parts = pathinfo('/www/htdocs/inc/lib.inc.php');
        dd($path_parts);


        dd(file_get_contents('https://www.php.net/manual/zh/function.file.php'));
          $row = 1;
          $handle = fopen("/home/vagrant/code/zhangfengxia/public/template/药物浏览记录导出.xlsx",'r');
          if($handle){
              while (($buffer = fgets($handle, 4096)) !== false) {
                  echo $buffer;
              }
              if (!feof($handle)) {
                  echo "Error: unexpected fgets() fail\n";
              }
              fclose($handle);
          }
    }

    public function arrayCollection(){
        $foo = array("bob"=>'你好', "fred", "jussi", "jouni");
        $records = [
            [
                'id' => 2135,
                'first_name' => 'John',
                'last_name' => 'Doe',
            ],
            [
                'id' => 3245,
                'first_name' => 'Sally',
                'last_name' => 'Smith',
            ],
            [
                'id' => 5342,
                'first_name' => 'Jane',
                'last_name' => 'Jones',
            ],
            [
                'id' => 5623,
                'first_name' => 'Peter',
                'last_name' => 'Doe',
            ]
        ];
        $array1 = array("a" => "green", "red", "blue", "fds"=>"3423",'klk','fygy','23456','erwtr');
        $array2 = array("b" => "green", "yellow", "red");
        $city  = "San Francisco";
        $state = "CA";
        $event = "SIGGRAPH";

        $location_vars = array("city", "state");

        /******       current + next + reset         *****/
        //current: 返回数组中的当前单元,每个数组中都有一个内部的指针指向它“当前的”单元，初始指向插入到数组中的第一个单元
        //next :将数组中的内部指针向前移动一位(即向右移动一位),即返回数组中下一个数组单元的值
        //reset :将数组内部指针倒回到第一个单元并返回第一个数组单元的值
        dd(current($array1), next($array1),current($array1),reset($array1),current($array1)); //green;red;red;green;green

        /******       range：根据范围创建数组，包含指定的元素         *****/
        dd(range(1,5), range(1,10,2), range('a','j'));

        /******       list：把数组中的值复制给一组变量         *****/
        list($a,$b,$cc) = $array1;
        dd($a,$b,$cc); //从左到右赋值，但是会跳过索引，从索引为0的开始

        /******       compact：建立一个数组，包括变量名和它们的值         *****/
        dd(compact('event', $location_vars)); //接受可变的参数条目，可以是一个包含变量名的字符串，也可以是一个包含变量名的数组，该数组也可以包含其他内容为变量名的数组，compact可以递归处理

        /******       array_map：为数组的每个元素应用回调函数         *****/
        dd(array_map(function ($var){
            return $var.'12345';
        }, $array2));

        /******       array_filter：用回调函数过滤数组中的单元         *****/
        /******       array_key_last：获取一个数组的最后一个键值         *****/
        $new_array = array_filter($array1,function ($var){
            return  (strlen($var) - 3);
        });//将array中满足callback条件的数组返回为新的数组，键名不变
        dd($new_array, array_key_last(($new_array)));

        /******       array_diff：计算两个数组的差集         *****/
        /******       array_intersect：计算两个数组的交集         *****/
        dd( array_diff($array1, $array2), array_intersect($array1,$array2)); //存在与第一参数中但是不存在第二个或者更多参数中的值，值对应的索引不变

        /******       array_combine：创建一个数组，用一个数组的值作为键名，另一个数组的值作为其值         *****/
        dd(array_combine($foo, $records)); //一参为新数组的key，第二参为值

        /******       array_column :返回数组中指定的一列         *****/
        dd(array_column($records, 'first_name')); //返回数据中键值为first_name的列，数组形式返回
        dd(array_column($records,'last_name','id'));//同样是返回键名为last_name列，不过键名是以id列为键名


        /******       array_chunk:将一个数组分割成多个         *****/
        dd(array_chunk($foo,2,true));//第三参数默认false，true会保持原来的键名

        /******       each         *****/
        $bar = each($foo);
        var_dump($bar);
    }


    public function phpZval(){
        echo '测试字符串引用计数';
        $a = "new string";
        $b = $a;
        xdebug_debug_zval( 'a' ); //1
        unset( $b);
        xdebug_debug_zval( 'a' );//1
        $b = &$a;
        xdebug_debug_zval( 'a' );//2
        echo '测试数组引用计数';
        $c = array('a','b');
        xdebug_debug_zval( 'c' );//refcount=2，但是数组内的键值对不变
        $d = $c;
        xdebug_debug_zval( 'c' );//2
        $c[2]='c';
        xdebug_debug_zval( 'c' );//1，数组改变值以后，之前引用全部作废，重新计算
        echo '测试int型计数';
        $e = 1;
        xdebug_debug_zval( 'e' );//0,int不计数引用次说
        die;


        //php进行内存管理的核心算法有两个： 一是引用技术，而是写时拷贝；当你申明一个php变量的时候，C语言就在底层给你新建了一个叫做zval的struct；如果给变量复制了，那么就会在底层给你建一个叫zend_value的union（联合体）
        $a = 'hello'.mt_rand(1,100);
        $b = $a;
        echo xdebug_debug_zval('a');
        echo xdebug_debug_zval('b');

        $a = '123'.mt_rand(1,100);
        echo xdebug_debug_zval('a');
        echo xdebug_debug_zval('b');
        die;
    }

    public function sortAlgorithm(){

        //阶乘求值算法
        /*
         function F($n){
        if($n = 0)return 1;
        }else{
        return $n*F($n-1)
        }
        var_dump(F(5));die;
         * */

        $arr=array(1,43,54,62,21,66,32,78,36,76,39);
        $length = count($arr);

        //快速排序:选择一个基准元素，通常选择第一个或最后一个。将待排序的以基准元素分为两部分，而此时基准元素正好在排好序的正确位置，然后同样的方法递归排序划分的两部分
        if($length <=1) return $arr;
        $base_num = $arr[0];//选择一个基准
        $left_num = [];//小于基准的
        $right_num = [];//大于基准的
         //遍历除标尺外的所有元素，按照大小关系放入两个数组中
        for($i=1 ; $i<$length; $i++){
            if($base_num > $arr[$i]){
                $left_num[] = $arr[$i];
            }else{
                $right_num[] = $arr[$i];
            }
        }
        //已经根据基准数通过第一轮比较，分成了两个数组，那么接下来是对左右数组内部再次排序
        $left_num = $this->sortAlgorithm($arr);
        $right_num = $this->sortAlgorithm($arr);
        return array_merge($left_num,[$base_num],$right_num);



        //选择排序：在要排序的一组数中，选出最小的与第一位置交换，然后在剩下的数中找到最小的与第二为止交换，依次类推，一直到倒数第二个数与最后一个数比较
        for ($i=0; $i< $length-1; $i++){//控制需要需要对比的轮数
            $p = $i;//现假设最小的值的位置
            for($j=$i+1; $j<$length; $j++){//控制每一轮对比的次数
                if($arr[$p] > $arr[$j]){
                    //发现比预定的更小的值，直接交换，下次比较用这个最小的
                    $p = $j;
                }
            }
            if($p != $i){
                //已经确定了最小值的位置，保存在$p中。要是发现最小值的位置与初设定的不一样，交换
                $tmp = $arr[$p];
                $arr[$p] = $arr[$i];
                $arr[$i] = $tmp;
            }
        }
        return $arr;



        //冒泡排序：从前往后对相邻的两个数依次进行比较调整，让较大的数下沉，较小的数往上冒。每当相邻两个数比较发现他们的排序与要求的相反，就互换


        for($i=0 ; $i<$length-1; $i++){//循环控制需要冒泡的次数
            for($k=0 ; $k<$length-$i-1; $k++){//该层控制每一轮冒出一个数时，需要比较的次数，比如第一轮：1需要跟后面各个数进行比较，比较次说为length-1-1；
                if($arr[$k] > $arr[$k+1]){
                    $tmp=$arr[$k+1];
                    $arr[$k+1]=$arr[$k];
                    $arr[$k]=$tmp;
                }
            }
        }
        return $arr;
    }


    public function testConstruct(){
$a = '2';
$b = '111';
        dd($a  > $b);


        $case1 = LearnController::fromBasicData(5,'name');
        $case2 = LearnController::formJson('{
"id": 15,
"name": "企业微信"
}');
        var_dump($case1,$case2);
        $case2 = null;//前面初始化了对象，这边再赋空，其实是会调用destruct析构函数
//        $case1 = null;
        //某个对象的所有引用都被删除或者当对象被显示销毁时执行析构函数

    }
}
